/******************************************************************************/
/*  mb.h                                                                      */
/*                                                                            */
/*  FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU. */
/*  Copyright (c) 2006 Christian Walter <wolti@sil.at>                        */
/*  All rights reserved.                                                      */
/******************************************************************************/

#ifndef __MB_H
#define __MB_H


#include "port\port.h"
#include "mbport.h"
#include "mbproto.h"


#ifdef __cplusplus
  PR_BEGIN_EXTERN_C
#endif


/*
 *  This module defines the interface for the application. It contains
 *  the basic functions and types required to use the Modbus protocol stack.
 *  A typical application will want to call ModbusInit() first. If the device
 *  is ready to answer network requests it must then call ModbusEnable()
 *  to activate the protocol stack. In the main loop the function ModbusPoll()
 *  must be called periodically.
 *
 *  The time interval between pooling depends on the configured
 *  Modbus timeout. If an RTOS is available a separate task should be created
 *  and the task should always call the function ModbusPoll().
 *
 *  Initialize protocol stack in RTU mode for a slave with address 10 = 0x0A
 *  ModbusInit(MB_RTU, 0x0A, 38400, MB_PAR_EVEN);
 *
 *  // Enable the Modbus Protocol Stack.
 *  ModbusEnable(...);
 *  for(;;)
 *  {
 *      // Call the main polling loop of the Modbus protocol stack.
 *      ModbusPoll(...);
 *      ...
 *  };
 */


/******************************************************************************/
/*      Defines                                                               */
/******************************************************************************/

/*  Use the default Modbus TCP port (502)
 */
#define MB_TCP_PORT_USE_DEFAULT 0


/******************************************************************************/
/*      Type definitions                                                      */
/******************************************************************************/

/*  Modbus serial transmission modes (RTU/ASCII).
 *
 *  Modbus serial supports two transmission modes. Either ASCII or RTU. RTU
 *  is faster but has more hardware requirements and requires a network with
 *  a low jitter. ASCII is slower and more reliable on slower links (E.g. modems)
 */
typedef enum
{
    MB_RTU = 0,                 // RTU transmission mode
    MB_ASCII,                   // ASCII transmission mode
    MB_TCP                      // TCP mode
} eMB_MODE;


/*  If register should be written or read.
 *
 *  This value is passed to the callback functions which support either
 *  reading or writing register values. Writing means that the application
 *  registers should be updated and reading means that the modbus protocol
 *  stack needs to know the current register values.
 *
 *  See MbRegHoldingCb(), MbRegCoilsCb(), MbRegDiscreteCb(), MbRegInputCb().
 */
typedef enum
{
    MB_REG_READ,                // Read register values and pass to protocol stack
    MB_REG_WRITE                // Update register values
} eMB_REGISTER_MODE;


/*  Errorcodes used by all function in the protocol stack.
 */
typedef enum
{
    MB_ENOERR = 0,              // no error
    MB_ENOREG,                  // illegal register address
    MB_EINVAL,                  // illegal argument
    MB_EPORTERR,                // porting layer error
    MB_ENORES,                  // insufficient resources
    MB_EIO,                     // I/O error
    MB_EILLSTATE,               // protocol stack in illegal state
    MB_ACKNOWLEDGE,             // cmd processing
    MB_ETIMEDOUT                // timeout error occurred
} eMB_ERROR_CODE;


/******************************************************************************/
/*      Function prototypes                                                   */
/******************************************************************************/

/*  Initialize the Modbus protocol stack.
 *
 *  This functions initializes the ASCII or RTU module and calls the
 *  init functions of the porting layer to prepare the hardware. Please
 *  note that the receiver is still disabled and no Modbus frames are
 *  processed until eMBEnable( ) has been called.
 *
 *  _mode - if ASCII or RTU mode should be used.
 *  _slaveAddress - the slave address. Only frames sent to this
 *    address or to the broadcast address are processed.
 *  _port - the port to use. E.g. 1 for COM1 on windows. This value
 *    is platform dependent and some ports simply choose to ignore it.
 *  _baudRate - the baudrate. E.g. 19200. Supported baudrates depend
 *    on the porting layer.
 *  _parity - parity used for serial transmission.
 *
 *  If no error occurs the function returns - eMB_ERROR_CODE::MB_ENOERR.
 *  The protocol is then in the disabled state and ready for activation
 *  by calling ModbusEnable(). Otherwise one of the following error codes 
 *  is returned:
 *    - eMB_ERROR_CODE::MB_EINVAL - if the slave address was not valid. Valid
 *        slave addresses are in the range 1 - 247.
 *    - eMB_ERROR_CODE::MB_EPORTERR - iF the porting layer returned an error.
 */
eMB_ERROR_CODE ModbusInit(const uint8_t _slaveAddress,
                          const uint32_t _baudRate,
                          const eMB_PARITY _parity);


/*  Initialize the Modbus protocol stack for Modbus TCP.
 *
 *  This function initializes the Modbus TCP Module. Please note that
 *  frame processing is still disabled until eMBEnable( ) is called.
 *
 *  _tcpPort - the TCP port to listen on.
 *  
 *  If the protocol stack has been initialized correctly the function
 *  returns eMB_ERROR_CODE::MB_ENOERR. Otherwise one of the following error
 *  codes is returned:
 *    - eMB_ERROR_CODE::MB_EINVAL If the slave address was not valid. Valid
 *        slave addresses are in the range 1 - 247.
 *    - eMB_ERROR_CODE::MB_EPORTERR IF the porting layer returned an error.
 */
eMB_ERROR_CODE ModbusTcpInit(const uint16_t _tcpPort);



/*  Release resources used by the protocol stack.
 *
 *  This function disables the Modbus protocol stack and release all
 *  hardware resources. It must only be called when the protocol stack 
 *  is disabled. 
 *
 *  Note all ports implement this function. A port which wants to 
 *  get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
 *
 *  If the resources where released it return eMB_ERROR_CODE::MB_ENOERR.
 *  If the protocol stack is not in the disabled state it returns
 *  eMB_ERROR_CODE::MB_EILLSTATE.
 */
eMB_ERROR_CODE ModbusClose(void);



/*  Enable the Modbus protocol stack.
 *
 *  This function enables processing of Modbus frames. Enabling the protocol
 *  stack is only possible if it is in the disabled state.
 *
 *  If the protocol stack is now in the state enabled it returns 
 *  eMB_ERROR_CODE::MB_ENOERR. If it was not in the disabled state it 
 *  return eMB_ERROR_CODE::MB_EILLSTATE.
 */
eMB_ERROR_CODE ModbusEnable(void);



/*  Disable the Modbus protocol stack.
 *
 *  This function disables processing of Modbus frames.
 *
 *  If the protocol stack has been disabled it returns 
 *  eMB_ERROR_CODE::MB_ENOERR. If it was not in the enabled state it returns
 *  eMB_ERROR_CODE::MB_EILLSTATE.
 */
eMB_ERROR_CODE ModbusDisable(void);



/*  The main pooling loop of the Modbus protocol stack.
 *
 *  This function must be called periodically. The timer interval required
 *  is given by the application dependent Modbus slave timeout. Internally the
 *  function calls xMbPortEventGet() and waits for an event from the receiver or
 *  transmitter state machines.
 *
 *  If the protocol stack is not in the enabled state the function
 *  returns eMB_ERROR_CODE::MB_EILLSTATE. Otherwise it returns 
 *  eMB_ERROR_CODE::MB_ENOERR.
 */
eMB_ERROR_CODE ModbusPoll(void);


/*  Configure the slave id of the device.
 *
 *  This function should be called when the Modbus function Report Slave ID
 *  is enabled (By defining MB_FUNC_OTHER_REP_SLAVEID_ENABLED in mbconfig.h).
 *
 *  _slaveID - values is returned in the Slave ID> byte of the
 *   Report Slave ID response.
 *  _xIsRunning - if TRUE the Run Indicator Status> byte is set to 0xFF.
 *   otherwise the Run Indicator Status is 0x00.
 *  _pAdditional - values which should be returned in the Additional
 *   bytes of the Report Slave ID response.
 *  _additionalLen - length of the buffer _pAdditonal.
 *
 *  If the static buffer defined by MB_FUNC_OTHER_REP_SLAVEID_BUF in
 *  mbconfig.h is to small it returns eMB_ERROR_CODE::MB_ENORES. Otherwise
 *  it returns eMB_ERROR_CODE::MB_ENOERR.
 */
eMB_ERROR_CODE ModbusSetSlaveID(const uint8_t _slaveID,
                                const bool_t _xIsRunning,
                                uint8_t const * _pAdditional,
                                const uint16_t _additionalLen);



/*  Registers a callback handler for a given function code.
 *
 *  This function registers a new callback handler for a given function code.
 *  The callback handler supplied is responsible for interpreting the Modbus PDU and
 *  the creation of an appropriate response. In case of an error it should return
 *  one of the possible Modbus exceptions which results in a Modbus exception frame
 *  sent by the protocol stack. 
 *
 *  _functionCode - the Modbus function code for which this handler should
 *   be registers. Valid function codes are in the range 1 to 127.
 *  _pxHandler The function handler which should be called in case
 *   such a frame is received. If NULL a previously registered function handler
 *   for this function code is removed.
 *
 *  eMB_ERROR_CODE::MB_ENOERR if the handler has been installed. If no
 *  more resources are available it returns eMB_ERROR_CODE::MB_ENORES. In this
 *  case the values in mbconfig.h should be adjusted. If the argument was not
 *  valid it returns eMB_ERROR_CODE::MB_EINVAL.
 */
eMB_ERROR_CODE MbRegisterCb(const uint8_t _functionCode,
                            pxMbFunctionHandler _pxHandler);



/******************************************************************************/
/*      Callback                                                              */
/******************************************************************************/

/*  The protocol stack does not internally allocate any memory for the
 *  registers. This makes the protocol stack very small and also usable on
 *  low end targets. In addition the values don't have to be in the memory
 *  and could for example be stored in a flash.
 *  Whenever the protocol stack requires a value it calls one of the callback
 *  function with the register address and the number of registers to read
 *  as an argument. The application should then read the actual register values
 *  (for example the ADC voltage) and should store the result in the supplied
 *  buffer.
 *  If the protocol stack wants to update a register value because a write
 *  register function was received a buffer with the new register values is
 *  passed to the callback function. The function should then use these values
 *  to update the application register values.
 */


/*  Callback function used if the value of a Input Register
 *  is required by the protocol stack. The starting register address is given
 *  by address and the last register is given by address + numRegs - 1.
 *
 *  _pRegBuffer - a buffer where the callback function should write
 *    the current value of the modbus registers to.
 *  _address - the starting address of the register. Input registers
 *    are in the range 1 - 65535.
 *  _numRegs - number of registers the callback function must supply.
 *
 *  The function must return one of the following error codes:
 *   - eMB_ERROR_CODE::MB_ENOERR If no error occurred. In this case a normal
 *       Modbus response is sent.
 *   - eMB_ERROR_CODE::MB_ENOREG If the application can not supply values
 *       for registers within this range. In this case a ILLEGAL DATA ADDRESS
 *       exception frame is sent as a response.
 *   - eMB_ERROR_CODE::MB_ETIMEDOUT If the requested register block is
 *       currently not available and the application dependent response
 *       timeout would be violated. In this case a SLAVE DEVICE BUSY
 *       exception is sent as a response.
 *   - eMB_ERROR_CODE::MB_EIO If an unrecoverable error occurred. In this case
 *       a SLAVE DEVICE FAILURE exception is sent as a response.
 */
eMB_ERROR_CODE ModbusRegInputCb(uint8_t * _pRegBuffer,
                                const uint16_t _address,
                                const uint16_t _numRegs);


/*  Callback function used if the value of a Input Register
 *  is required by the protocol stack. The starting register address is given
 *  by address and the last register is given by address + numRegs - 1.
 *
 *  _pRegBuffer - if the application registers values should be updated the
 *    buffer points to the new registers values. If the protocol stack needs
 *    to now the current values the callback function should write them into
 *    this buffer.
 *  _address - the starting address of the register.
 *  _numRegs - number of registers to read or write.
 *  _mode - if eMB_REGISTER_MODE::MB_REG_WRITE the application register 
 *    values should be updated from the values in the buffer. For example
 *    this would be the case when the Modbus master has issued an 
 *    WRITE SINGLE REGISTER command.
 *    If the value eMB_REGISTER_MODE::MB_REG_READ the application should copy 
 *    the current values into the buffer _pRegBuffer.
 *
 *  The function must return one of the following error codes:
 *   - eMB_ERROR_CODE::MB_ENOERR If no error occurred. In this case a normal
 *       Modbus response is sent.
 *   - eMB_ERROR_CODE::MB_ENOREG If the application can not supply values
 *       for registers within this range. In this case a ILLEGAL DATA ADDRESS
 *       exception frame is sent as a response.
 *   - eMB_ERROR_CODE::MB_ETIMEDOUT If the requested register block is
 *       currently not available and the application dependent response
 *       timeout would be violated. In this case a SLAVE DEVICE BUSY
 *       exception is sent as a response.
 *   - eMB_ERROR_CODE::MB_EIO If an unrecoverable error occurred. In this case
 *       a SLAVE DEVICE FAILURE exception is sent as a response.
 */
eMB_ERROR_CODE ModbusRegHoldingCb(uint8_t * _pRegBuffer,
                                  const uint16_t _address,
                                  const uint16_t _numRegs,
                                  const eMB_REGISTER_MODE _mode);


/*  Callback function used if a Coil Register value is
 *  read or written by the protocol stack. If you are going to use
 *  this function you might use the functions xMbUtilSetBits() and
 *  xMbUtilGetBits() for working with bitfields.
 *
 *  _pRegBuffer - the bits are packed in bytes where the first coil
 *   starting at address _address is stored in the LSB of the
 *   first byte in the buffer _pRegBuffer.
 *   If the buffer should be written by the callback function unused
 *   coil values (I.e. if not a multiple of eight coils is used) should be set
 *   to zero.
 *  _address - the first coil number.
 *  _numCoils - number of coil values requested.
 *  _mode - if eMB_REGISTER_MODE::MB_REG_WRITE the application values should
 *   be updated from the values supplied in the buffer _pRegBuffer.
 *   If eMB_REGISTER_MODE::MB_REG_READ the application should store the current
 *   values in the buffer _pRegBuffer.
 *
 *  The function must return one of the following error codes:
 *   - eMB_ERROR_CODE::MB_ENOERR If no error occurred. In this case a normal
 *       Modbus response is sent.
 *   - eMB_ERROR_CODE::MB_ENOREG If the application does not map an coils
 *       within the requested address range. In this case a ILLEGAL DATA ADDRESS
 *       is sent as a response.
 *   - eMB_ERROR_CODE::MB_ETIMEDOUT If the requested register block is
 *       currently not available and the application dependent response
 *       timeout would be violated. In this case a SLAVE DEVICE BUSY
 *       exception is sent as a response.
 *   - eMB_ERROR_CODE::MB_EIO If an unrecoverable error occurred. In this case
 *       a SLAVE DEVICE FAILURE exception is sent as a response.
 */
eMB_ERROR_CODE ModbusRegCoilsCb(uint8_t * _pRegBuffer,
                                const uint16_t _address,
                                const uint16_t _numCoils,
                                const eMB_REGISTER_MODE _mode);


/*  Callback function used if a Input Discrete Register value is
 *  read by the protocol stack.
 *
 *  If you are going to use his function you might use the functions
 *  xMbUtilSetBits() and xMbUtilGetBits() for working with bitfields.
 *
 *  _pRegBuffer - the buffer should be updated with the current
 *   coil values. The first discrete input starting at _address must be
 *   stored at the LSB of the first byte in the buffer. If the requested number
 *   is not a multiple of eight the remaining bits should be set to zero.
 *  _address - the starting address of the first discrete input.
 *  _numDiscrete - number of discrete input values.
 *
 *  The function must return one of the following error codes:
 *   - eMB_ERROR_CODE::MB_ENOERR If no error occurred. In this case a normal
 *       Modbus response is sent.
 *   - eMB_ERROR_CODE::MB_ENOREG If no such discrete inputs exists.
 *       In this case a ILLEGAL DATA ADDRESS exception frame is sent 
 *       as a response.
 *   - eMB_ERROR_CODE::MB_ETIMEDOUT If the requested register block is
 *       currently not available and the application dependent response
 *       timeout would be violated. In this case a SLAVE DEVICE BUSY
 *       exception is sent as a response.
 *   - eMB_ERROR_CODE::MB_EIO If an unrecoverable error occurred. In this case
 *       a SLAVE DEVICE FAILURE exception is sent as a response.
 */
eMB_ERROR_CODE ModbusRegDiscreteCb(uint8_t * _pRegBuffer,
                                   const uint16_t _address,
                                   const uint16_t _numDiscrete);



#ifdef __cplusplus
  PR_END_EXTERN_C
#endif


#endif